<template>
  <ThreeBox ref="container"></ThreeBox>
</template>

<script setup>
import ThreeBox from "../../components/ThreeBox.vue";
import { ref, onMounted } from "vue";
import * as THREE from "../../third/three/three.module.js";
import { FontLoader } from "../../third/three/jsm/loaders/FontLoader.js";
import { TextGeometry } from "../../third/three/jsm/geometries/TextGeometry.js";

const container = ref(null);
let threeBox = null;
let threePara = null;
let scene = new THREE.Scene();
let parameters = null;
let materials = [];
let points = [];
let mouseX = 0;
let mouseY = 0;

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  threePara.camera.position.x += (-mouseX - threePara.camera.position.x) * 0.02;
  threePara.camera.position.y += (mouseY - threePara.camera.position.y) * 0.02;
  threePara.camera.lookAt(0, 0, 0);

  let time = Date.now() * 0.00005;
  for (let i = 0; i < materials.length; i++) {
    points[i].rotation.y = time * (i < 4 ? i + 1 : -(i + 1));

    //动态改变颜色
    let color = parameters[i][0];
    let h = ((360 * (color[0] + time)) % 360) / 360;
    materials[i].color.setHSL(h, color[1], color[2]);
  }
  threePara.renderer.render(scene, threePara.camera);
}

function init() {
  //纹理图片
  let textureLoader = new THREE.TextureLoader();
  let sprite1 = textureLoader.load("./three/textures/snowflake1.png");
  let sprite2 = textureLoader.load("./three/textures/snowflake2.png");
  let sprite3 = textureLoader.load("./three/textures/snowflake3.png");
  let sprite4 = textureLoader.load("./three/textures/snowflake4.png");
  let sprite5 = textureLoader.load("./three/textures/snowflake5.png");
  parameters = [
    [[1.0, 0.2, 0.5], sprite2, 20],
    [[0.95, 0.1, 0.5], sprite3, 15],
    [[0.9, 0.05, 0.5], sprite1, 10],
    [[0.85, 0, 0.5], sprite5, 8],
    [[0.8, 0, 0.5], sprite4, 5],
  ];

  //生成点
  let vertices = [];
  let bufferGeo = new THREE.BufferGeometry();
  for (let i = 0; i < 9000; i++) {
    vertices.push(Math.random() * 2000 - 1000);
  }
  bufferGeo.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(vertices, 3)
  );

  //添加点
  for (let i = 0; i < parameters.length; i++) {
    let color = parameters[i][0];
    materials[i] = new THREE.PointsMaterial({
      map: parameters[i][1],
      size: parameters[i][2],
      blending: THREE.AdditiveBlending,
      depthTest: false,
      transparent: true,
    });
    materials[i].color.setHSL(color[0], color[1], color[2]);

    let point = new THREE.Points(bufferGeo, materials[i]);
    point.rotation.x = Math.random() * 6;
    point.rotation.y = Math.random() * 6;
    point.rotation.z = Math.random() * 6;
    points.push(point);
    scene.add(point);
  }

  //文字
  let loader = new FontLoader();
  loader.load("./three/fonts/KaiTi_Regular.json", function (font) {
    let textGeo = new TextGeometry("凛冬将至", {
      font: font,
      size: 80,
      height: 5,
      curveSegments: 12,
      bevelEnabled: true,
      bevelSegments: 5,
    });

    let materials = [
      new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }),
      new THREE.MeshPhongMaterial({ color: 0xffffff }),
    ];

    //相对中心偏移
    textGeo.computeBoundingBox();
    let centerOffset =
      -0.5 * (textGeo.boundingBox.max.x - textGeo.boundingBox.min.x);

    let textMesh = new THREE.Mesh(textGeo, materials);
    textMesh.position.set(centerOffset, 0, 0);

    scene.add(textMesh);
  });

  //光源
  let dirLight = new THREE.DirectionalLight(0xffffff, 1);
  dirLight.position.set(0, 1, 1).normalize();
  scene.add(dirLight);

  //相机
  threePara.camera = new THREE.PerspectiveCamera(
    45,
    threeBox.clientWidth / threeBox.clientHeight,
    1,
    2000
  );
  threePara.camera.position.set(0, 0, 1000);
  threePara.camera.lookAt(0, 0, 0);

  //渲染器
  threePara.renderer = new THREE.WebGLRenderer();
  threePara.renderer.setPixelRatio(window.devicePixelRatio);
  threePara.renderer.setSize(threeBox.clientWidth, threeBox.clientHeight);
  threeBox.appendChild(threePara.renderer.domElement);

  threeBox.addEventListener("mousemove", function (event) {
    mouseX = event.layerX - threeBox.clientWidth / 2;
    mouseY = event.layerY - threeBox.clientHeight / 2;
  });
}

onMounted(() => {
  threeBox = container.value.threeBox;
  threePara = container.value.threePara;
  init();
  animate();
});
</script>
